//888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
//
//	File		 :	Set32Byte.h
//	Contents	 :	Source file for CSet32Byte, a class which allow the fast manipulation
//						of a set of 30, each of which can hold a value up to 256
//					The last byte is reserved for pointing to the maximum value
//	Creation Date:	22/12/1999
//	Last Modified:	23/12/1999	lg
//	tabs width	 :	every 4 unsigned characters
//
//888888888888888888888888888888888888888888888888888888888888888888888888888888888888888

#include <memory>
#include <cassert>

union CSet32Byte
{
	unsigned char	c[32];
	unsigned long	u[8];
	void	Clear()				{	FlagAll((unsigned char)0);			}
	void	SetFlag(int pos)	{	c[pos] = '\xff';		}
	unsigned char	GetMaxCnt()	const	{	return c[GetMaxIndex()];	}
	unsigned char	GetMaxIndex() const	{	return c[31];				}
	void	FlagAll(int c);
	void	INTERSECT(const CSet32Byte& s1, const CSet32Byte& s2) {AND(s1,s2);}
	void	AND(const CSet32Byte& s1, const CSet32Byte& s2);
	void	OR(const CSet32Byte& s1, const CSet32Byte& s2);
	unsigned char	IsFlagged(unsigned long	i) const;
	void 	IncFlag(unsigned long i);
	unsigned long	Total() const;
	int		ToInt() const;
};

inline 	unsigned char CSet32Byte::IsFlagged(unsigned long i) const
{
	assert(i < 31);
	return c[i];
}

inline void CSet32Byte::IncFlag(unsigned long i)
{
	assert(i < 31);
	++c[i];
	if (c[i] > c[c[31]])
		c[31] = (unsigned char)i;
}

// get the most frequent residue
inline void CSet32Byte::FlagAll(int c)
{
	memset(this, c, sizeof(CSet32Byte));
}

inline void CSet32Byte::AND(const CSet32Byte& s1, const CSet32Byte& s2)
{
	for (unsigned long i = 0; i < 8; ++i)
		u[i] = s1.u[i] & s2.u[i];
}

inline void CSet32Byte::OR(const CSet32Byte& s1, const CSet32Byte& s2)
{
	for (unsigned long i = 0; i < 8; ++i)
		u[i] = s1.u[i] | s2.u[i];
}

inline unsigned long CSet32Byte::Total() const
{
	unsigned long result = 0;
	for (unsigned long i = 0; i < 8; ++i)
		result += u[i];
	result = (result & 0x0000FFFF) + (result >> 16);
	result = (result & 0x0000FF)	+ (result >> 8);
	return result;
}







union CSet32Short
{
	// last word stores the index of the maximum value
	// remember to memset0 (i.e. clear)
	unsigned short	w[32];
	unsigned long	u[16];
	void			Clear()						{	FlagAll((unsigned short)0);			}
	void			SetFlag(unsigned long pos)	{	w[pos] = (unsigned short)0xffff;	}
	unsigned short	GetMaxCnt()	const			{	return w[GetMaxIndex()];			}
	unsigned short	GetMaxIndex() const			{	return w[31];						}
	void			FlagAll(unsigned short w);
	void			INTERSECT(const CSet32Short& s1, const CSet32Short& s2) {AND(s1,s2);}
	void			AND(const CSet32Short& s1, const CSet32Short& s2);
	void			OR(const CSet32Short& s1, const CSet32Short& s2);
	unsigned short	IsFlagged(unsigned long i) const;
	void 			IncFlag(unsigned long i);
	unsigned long	Total() const;
	unsigned long	TotalAlpha() const;
	int				ToInt() const;
};

inline 	unsigned short CSet32Short::IsFlagged(unsigned long i) const
{
	assert(i < 31);
	return w[i];
}

inline void CSet32Short::IncFlag(unsigned long i)
{
	assert(i < 31);
	++w[i];
	if (w[i] > w[w[31]])
		w[31] = (unsigned short)i;
}

// get the most frequent residue
inline void CSet32Short::FlagAll(unsigned short w)
{
	memset(this, w, sizeof(CSet32Short));
}

inline void CSet32Short::AND(const CSet32Short& s1, const CSet32Short& s2)
{
	for (int i = 0; i < 16; ++i)
		u[i] = s1.u[i] & s2.u[i];
//	for (int i = 0; i < 32; ++i)
//		w[i] = s1.w[i] & s2.w[i];
}

inline void CSet32Short::OR(const CSet32Short& s1, const CSet32Short& s2)
{
//	for (int i = 0; i < 32; ++i)
//		w[i] = s1.w[i] | s2.w[i];
	for (int i = 0; i < 16; ++i)
		u[i] = s1.u[i] | s2.u[i];
}

inline unsigned long CSet32Short::Total() const
{

	unsigned long result = 0;
//	for (int i = 0; i < 16; ++i)
//		result += u[i];
//	result = (result & 0x0000FFFF) + (result >> 16);
	for (int i = 0; i < 32; ++i)
		result += w[i];
	return result;
}

inline unsigned long CSet32Short::TotalAlpha() const
{
	unsigned long result = 0;
//	for (int i = 0; i < 26; ++i)
//		result += w[i];

	for (int i = 0; i < 13; ++i)
		result += u[i];
	result = (result & 0x0000FFFF) + (result >> 16);
	return result;
}
